package com.kun.video.util;

import cn.hutool.core.text.StrPool;
import com.kun.video.Main;
import com.kun.video.exception.Assert;
import com.kun.video.exception.BizException;
import javafx.event.EventTarget;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.stream.Collectors;

/**
 * 深度优化的CSS管理工具，支持主题管理、资源预加载和LRU缓存。
 * 主要功能包括：
 * - 单例模式确保全局唯一实例
 * - 通过LRU缓存机制缓存最多50个CSS资源路径，提高加载效率
 * - 注册和管理多个主题，支持动态切换
 * - 预加载CSS资源，减少运行时延迟
 * - 管理节点样式表的优先级和生命周期
 * - 自动处理资源路径解析和异常处理
 *
 * @author gzc
 */
public final class CssManager {
    private static final Logger log = LoggerFactory.getLogger(CssManager.class);
    private static final int MAX_CACHE_SIZE = 50;
    public static final ThemeEnum DEFAULT_THEME = ThemeEnum.LIGHT;
    public static final String CSS_FILE_PARENT_PATH = "css/";
//    public static final String CSS_FILE_PARENT_PATH = "/css/";
    /**
     * 双重校验锁单例模式，确保线程安全
     */
    private static volatile CssManager instance;

    /**
     * LRU缓存，最近最少使用策略，线程安全
     */
    private final Map<String, String> lruCache = Collections.synchronizedMap(
            new LinkedHashMap<>(MAX_CACHE_SIZE, 0.75f, true) {
                @Override
                protected boolean removeEldestEntry(Map.Entry eldest) {
                    return size() > MAX_CACHE_SIZE;
                }
            });

    /**
     * 预加载资源集合，写时复制保证线程安全
     */
    private final Set<String> preloadedResources = new CopyOnWriteArraySet<>();
    /**
     * 主题注册表，Key为主题名称
     */
    private final Map<String, Theme> themeRegistry = new ConcurrentHashMap<>(16);
    /**
     * 节点样式注册表，记录每个节点应用的样式路径
     */
    private final Map<EventTarget, Set<String>> nodeStylesRegistry = new ConcurrentHashMap<>(32);

    private CssManager() {
        log.info("加载css管理器");
        registerDefaultTheme();
    }

    /**
     * 获取CssManager单例实例
     */
    public static CssManager getInstance() {
        if (instance == null) {
            synchronized (CssManager.class) {
                if (instance == null) {
                    instance = new CssManager();
                }
            }
        }
        return instance;
    }

    /**
     * 加载CSS资源并缓存结果
     *
     * @param cssPath     资源路径，建议以"/"开头
     * @param forceReload 是否强制重新加载
     * @return CSS资源的完整URL，若未找到返回空字符串
     */
    public String loadCss(String cssPath, boolean forceReload) {
        if (!forceReload && lruCache.containsKey(cssPath)) {
            return lruCache.get(cssPath);
        }

        URL resourceUrl = Assert.notNull(resolveResource(cssPath), "css文件路径【{}】不存在文件!", cssPath);
        log.info("加载css文件: {} -> {}", cssPath, resourceUrl.toExternalForm());
        String cssUrl = resourceUrl.toExternalForm();
        lruCache.put(cssPath, cssUrl);
        log.debug("加载css文件: {} -> {}", cssPath, cssUrl);
        return cssUrl;
    }

    /**
     * 应用CSS样式到指定节点并设置优先级
     *
     * @param parent   目标节点，不可为null
     * @param cssPath  CSS资源路径
     * @param priority 优先级（0为最高），越界时自动调整到有效范围
     */
    public void applyStyles(Parent parent, String cssPath, int priority) {
        Objects.requireNonNull(parent, "Node cannot be null");
//        if (!Platform.isFxApplicationThread()) {
//            throw new IllegalStateException("必须在JavaFX应用线程中调用该方法");
//        }

        String cssUrl = loadCss(cssPath, false);
        if (cssUrl.isEmpty()) {
            return;
        }

        synchronized (parent) {
            List<String> stylesheets = new ArrayList<>(parent.getStylesheets());
            stylesheets.remove(cssUrl);
            // 确保优先级在合法范围内
            int adjustedPriority = Math.min(priority, stylesheets.size());
            stylesheets.add(adjustedPriority, cssUrl);
            ComUtil.uiThreadRun(() -> parent.getStylesheets().setAll(stylesheets));

            nodeStylesRegistry.computeIfAbsent(parent, k -> ConcurrentHashMap.newKeySet())
                    .add(cssPath);
        }
    }

    public void applyStyles(Scene scene, String cssPath, int priority) {
        Assert.notNull(scene, "scene为空");
        String cssUrl = loadCss(cssPath, false);
        if (cssUrl.isEmpty()) {
            return;
        }

        synchronized (scene) {
            List<String> stylesheets = new ArrayList<>(scene.getStylesheets());
            stylesheets.remove(cssUrl);
            // 确保优先级在合法范围内
            int adjustedPriority = Math.min(priority, stylesheets.size());
            stylesheets.add(adjustedPriority, cssUrl);
            ComUtil.uiThreadRun(() -> scene.getStylesheets().setAll(stylesheets));

            nodeStylesRegistry.computeIfAbsent(scene, k -> ConcurrentHashMap.newKeySet())
                    .add(cssPath);
        }
    }

    /**
     * 注册主题配置
     */
    public void registerTheme(String themeName, Theme theme) {
        themeRegistry.put(themeName, theme);
        log.info("注册主题 -> {}", themeName);
    }

    /**
     * 应用指定主题到根节点，自动清除原有样式
     */
    public void applyTheme(Parent rootNode, String themeName) {
        Theme theme = themeRegistry.get(themeName);
        if (theme == null) {
            log.warn("未找到主题 -> {}", themeName);
            return;
        }

        clearNodeStyles(rootNode);
        theme.getCssPaths().forEach(path -> {
            try {
                applyStyles(rootNode, path, 0);
            } catch (Exception e) {
                log.error("加载CSS发生异常 -> ", e);
            }
        });
    }

    /**
     * 预加载多个资源，避免重复加载
     */
    public void preloadResources(Collection<String> paths) {
        paths.parallelStream().forEach(path -> {
            if (preloadedResources.add(path)) {
                loadCss(path, false);
            }
        });
    }

    /**
     * 解除节点绑定的所有样式
     */
    public void unbindNodeStyles(Parent parent) {
        Set<String> paths = nodeStylesRegistry.remove(parent);
        if (paths != null) {
            paths.forEach(path -> removeStyle(parent, path));
        }
    }

    private URL resolveResource(String path) {
        if (!path.startsWith(StrPool.SLASH)) {
            log.warn("非标准的资源路径 -> {}", path);
            path = StrPool.SLASH + path;
        }
        return Main.class.getResource(path);
    }

    /**
     * 注册默认主题
     */
    private void registerDefaultTheme() {
        for (ThemeEnum themeEnum : ThemeEnum.values()) {
            registerTheme(themeEnum.getThemeName(), themeEnum.toTheme());
        }
    }

    private void clearNodeStyles(Parent node) {
        node.getStylesheets().clear();
        nodeStylesRegistry.remove(node);
    }

    /**
     * 移除节点上的指定样式
     */
    public void removeStyle(Parent node, String cssPath) {
        String cssUrl = lruCache.get(cssPath);
        if (cssUrl != null) {
            node.getStylesheets().remove(cssUrl);
        }
    }

    /**
     * 禁用焦点的边框样式
     */
    public void disableFocusedBorderStyle(Node node) {
        if (node == null) {
            log.warn("禁用焦点的边框样式失败，节点对象为空");
            return;
        }
        node.setStyle("""
                    -fx-focus-color: transparent;
                    -fx-faint-focus-color: transparent;
                    -fx-border-color: transparent;
                """);
    }

    /**
     * 主题枚举 - 定义系统支持的视觉主题
     */
    public enum ThemeEnum {
        /**
         * 暗黑主题
         */
        DARK("dark",
                "/css/dark-theme.css",
                "暗黑主题"),
        /**
         * 明亮主题
         */
        LIGHT("light",
                "/css/light-theme.css",
                "明亮主题");

        private final String themeName;
        private final String cssPath;
        private final String displayName;

        ThemeEnum(String themeName, String cssPath, String displayName) {
            this.themeName = themeName;
            this.cssPath = cssPath;
            this.displayName = displayName;
        }

        /**
         * 通过主题ID获取枚举实例
         *
         * @param themeId 主题标识符（不区分大小写）
         * @throws IllegalArgumentException 当主题ID不存在时抛出
         */
        public static ThemeEnum fromId(String themeId) {
            return Arrays.stream(values())
                    .filter(theme -> theme.themeName.equalsIgnoreCase(themeId))
                    .findFirst()
                    .orElseThrow(() -> new BizException("未知主题ID -> " + themeId));
        }

        /**
         * 转换为Theme配置对象
         */
        public Theme toTheme() {
            return new Theme.Builder(themeName)
                    .withCss(cssPath)
                    .build();
        }

        /**
         * 获取所有可用主题的显示名称列表
         */
        public static List<String> getDisplayNames() {
            return Arrays.stream(values())
                    .map(ThemeEnum::getDisplayName)
                    .collect(Collectors.toList());
        }

        public String getThemeName() {
            return themeName;
        }

        public String getCssPath() {
            return cssPath;
        }

        public String getDisplayName() {
            return displayName;
        }

    }

    /**
     * 主题配置类，用于管理一组CSS资源路径
     */
    public static class Theme {
        private final String name;
        private final List<String> cssPaths;

        /**
         * 私有构造函数，通过Builder构建实例
         */
        private Theme(Builder builder) {
            this.name = builder.name;
            // 创建不可修改的列表副本
            this.cssPaths = List.copyOf(builder.cssPaths);
        }

        /**
         * 获取主题名称
         */
        public String getName() {
            return name;
        }

        /**
         * 获取不可修改的CSS路径列表
         */
        public List<String> getCssPaths() {
            return cssPaths;
        }

        /**
         * 建造者模式实现类
         */
        public static class Builder {
            private final String name;
            private final List<String> cssPaths = new ArrayList<>();

            /**
             * 初始化建造者，必须指定主题名称
             *
             * @param name 主题名称（非空）
             */
            public Builder(String name) {
                this.name = Assert.notBlank(name, "主题名称为空");
            }

            /**
             * 添加单个CSS路径
             *
             * @param path CSS资源路径（非空）
             */
            public Builder withCss(String path) {
                Assert.notBlank(path, "CSS路径为空");
                cssPaths.add(path);
                return this;
            }

            /**
             * 批量添加CSS路径
             *
             * @param paths CSS路径集合（非空）
             */
            public Builder withCssPaths(Collection<String> paths) {
                Assert.notEmpty(paths, "CSS路径列表为空");
                // 防御性复制，防止外部修改影响建造者
                cssPaths.addAll(new ArrayList<>(paths));
                return this;
            }

            /**
             * 构建不可变Theme实例
             */
            public Theme build() {
                Assert.notEmpty(cssPaths, "至少需要指定一个CSS路径");
                return new Theme(this);
            }
        }
    }

}